Final Project: Analyzing Relationships between Vehicular Crashes and Speed Cameras

Final Project: Analyzing Relationships between Vehicular Crashes and Speed Cameras#


Haley Ventura
GGIS 407 Final Project

#import necessary libraries
%matplotlib inline
import geopandas
import os
import fiona
import pprint
import IPython
from matplotlib import pyplot as plt
import pandas as pd
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 2
      1 #import necessary libraries
----> 2 get_ipython().run_line_magic('matplotlib', 'inline')
      3 import geopandas
      4 import os

File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\IPython\core\interactiveshell.py:2480, in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth)
   2478     kwargs['local_ns'] = self.get_local_scope(stack_depth)
   2479 with self.builtin_trap:
-> 2480     result = fn(*args, **kwargs)
   2482 # The code below prevents the output from being displayed
   2483 # when using magics with decorator @output_can_be_silenced
   2484 # when the last Python token in the expression is a ';'.
   2485 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\IPython\core\magics\pylab.py:99, in PylabMagics.matplotlib(self, line)
     97     print("Available matplotlib backends: %s" % backends_list)
     98 else:
---> 99     gui, backend = self.shell.enable_matplotlib(args.gui.lower() if isinstance(args.gui, str) else args.gui)
    100     self._show_matplotlib_backend(args.gui, backend)

File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\IPython\core\interactiveshell.py:3658, in InteractiveShell.enable_matplotlib(self, gui)
   3637 """Enable interactive matplotlib and inline figure support.
   3638 
   3639 This takes the following steps:
   (...)
   3655     display figures inline.
   3656 """
   3657 from IPython.core import pylabtools as pt
-> 3658 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
   3660 if gui != 'inline':
   3661     # If we have our first gui selection, store it
   3662     if self.pylab_gui_select is None:

File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\IPython\core\pylabtools.py:320, in find_gui_and_backend(gui, gui_select)
    303 def find_gui_and_backend(gui=None, gui_select=None):
    304     """Given a gui string return the gui and mpl backend.
    305 
    306     Parameters
   (...)
    317     'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
    318     """
--> 320     import matplotlib
    322     has_unified_qt_backend = getattr(matplotlib, "__version_info__", (0, 0)) >= (3, 5)
    324     backends_ = dict(backends)

ModuleNotFoundError: No module named 'matplotlib'
#always check for location of files to ensure proper setup
TrafficCrashes = 'TrafficCrashes.shp'
if os.path.exists(TrafficCrashes):
    print('TrafficCrashes:', TrafficCrashes)
else:
    print('Please download the tutorial data or fix the path!')
TrafficCrashes: TrafficCrashes.shp
#read file
TrafficCrashes = geopandas.read_file(r"TrafficCrashes.shp")
#preview the data. Data is for 2022 only.
TrafficCrashes.head()
crash_reco date_crash time_crash posted_spe first_cras trafficway crash_type hit_and_ru damage prim_contr ... injuries_t injuries_f injuries_i injuries_n injuries_r injuries_2 injuries_u latitude longitude geometry
0 367490fad73ad47e7c570928f719c506c645fbf2099e14... 2022-12-31 23:59:00.000 20.0 PARKED MOTOR VEHICLE ONE-WAY NO INJURY / DRIVE AWAY Y OVER $1,500 UNABLE TO DETERMINE ... 0.0 0.0 0.0 0.0 0.0 1.0 0.0 41.937900 -87.792173 POINT (-87.79217 41.93790)
1 538cc213046ff7600cd3586a2ddd41c5b48f76f6ff5225... 2022-12-31 23:55:00.000 20.0 PARKED MOTOR VEHICLE UNKNOWN INJURY AND / OR TOW DUE TO CRASH Y OVER $1,500 UNABLE TO DETERMINE ... 1.0 0.0 0.0 1.0 0.0 1.0 0.0 41.912074 -87.775463 POINT (-87.77546 41.91207)
2 c05d09cfbb00c98d0890811b21cec65fefef70900c1d60... 2022-12-31 23:52:00.000 15.0 PARKED MOTOR VEHICLE NOT DIVIDED NO INJURY / DRIVE AWAY None $501 - $1,500 UNABLE TO DETERMINE ... 0.0 0.0 0.0 0.0 0.0 6.0 0.0 41.962269 -87.634734 POINT (-87.63473 41.96227)
3 5e5667bedce936fb6768c48cd1d1d71af618061fe0e476... 2022-12-31 23:45:00.000 30.0 PARKED MOTOR VEHICLE NOT DIVIDED NO INJURY / DRIVE AWAY Y OVER $1,500 UNABLE TO DETERMINE ... 0.0 0.0 0.0 0.0 0.0 1.0 0.0 41.744200 -87.566268 POINT (-87.56627 41.74420)
4 70741202005e9dc65235b75cc964f49922cf0b2739a70e... 2022-12-31 23:45:00.000 30.0 FIXED OBJECT DIVIDED - W/MEDIAN BARRIER NO INJURY / DRIVE AWAY Y OVER $1,500 NOT APPLICABLE ... 0.0 0.0 0.0 0.0 0.0 1.0 0.0 41.732755 -87.643378 POINT (-87.64338 41.73276)

5 rows × 27 columns

#learn about the data!
counts_per_day=TrafficCrashes.groupby('date_crash').size()
counts_per_daysummary= counts_per_day.sort_values(axis=0, ascending=False).head(20)
print(counts_per_daysummary)
date_crash
2022-12-09    456
2022-11-18    441
2022-10-25    437
2022-09-16    437
2022-05-13    432
2022-10-07    412
2022-11-15    405
2022-02-17    404
2022-05-06    400
2022-10-14    392
2022-09-02    391
2022-06-17    389
2022-12-16    388
2022-03-18    387
2022-09-30    385
2022-12-14    384
2022-10-11    379
2022-06-03    379
2022-06-16    377
2022-06-14    376
dtype: int64
#WOW! That's a lot of crashes
averagecrashday=counts_per_day.mean(axis=0)
print("The average number of vehicular crashes each day in Chicago in 2022 was %.f" % averagecrashday)
The average number of vehicular crashes each day in Chicago in 2022 was 294
#map the crashes
TrafficCrashes.plot(markersize=1, figsize=(14,12))
<Axes: >
_images/db0593e3f6917617948b189b600126e376f2f373d96435f7012fcc1b1e09e3a3.png
#based on the map above, we are not able to conclude much. there are a lot of dots and there are some areas, such as the loop and general grid of the city that are more solid.
#in order to see which areas have more crashes, we add the shapefile with ward boundaries
WardBoundaries = 'WardBoundaries.shp'
if os.path.exists(WardBoundaries):
    print('Ward Boundaries:', WardBoundaries)
else:
    print('Please download the tutorial data or fix the path!')
Please download the tutorial data or fix the path!
#read file
WardBoundaries = geopandas.read_file(r"WardBoundaries.shp")
#preview the data
WardBoundaries.head()
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928...
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904...
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865...
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876...
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766...
#review the data based on shape area. The wards are all different sizes, so this will affect our results.
#A ward with a larger geographic area is likely to have more crashes, but that does not mean the frequency of crashes is worse.
WardBoundaries.sort_values(by=['st_area_sh'],axis=0, ascending=False)
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry
9 10.0 60.0 2022-06-01 00:00:00.000 10.0 {19FF2026-6DDD-45DA-8DF6-B44B0C15834C} 5.773395e+08 147455.404991 POLYGON ((-87.53018 41.74310, -87.53008 41.742...
40 41.0 91.0 2022-06-01 00:00:00.000 41.0 {C885247A-E064-4FCF-A35A-747DEC142421} 4.754967e+08 218605.417697 POLYGON ((-87.79065 42.00040, -87.79058 42.000...
8 9.0 59.0 2022-06-01 00:00:00.000 9.0 {B75B90E6-CB95-4890-BBC3-D2F313E2EE80} 2.344895e+08 102227.294779 POLYGON ((-87.61414 41.72189, -87.61414 41.721...
18 19.0 69.0 2022-06-01 00:00:00.000 19.0 {91001AF5-B4E0-4F45-A1CB-7C22070BA22D} 2.199899e+08 101405.125517 POLYGON ((-87.66674 41.73022, -87.66677 41.730...
20 21.0 71.0 2022-06-01 00:00:00.000 21.0 {BA7C81E8-7DEB-46DF-8E71-95F9AE112FF3} 2.118767e+08 92642.006031 POLYGON ((-87.62405 41.73014, -87.62410 41.730...
17 18.0 68.0 2022-06-01 00:00:00.000 18.0 {E22B6995-91F8-4C49-A9F3-4085D503F2A4} 1.933789e+08 79337.751930 POLYGON ((-87.65830 41.73950, -87.65834 41.739...
38 39.0 89.0 2022-06-01 00:00:00.000 39.0 {15480A27-2480-40CF-91EC-72B090F03522} 1.818672e+08 77704.757487 POLYGON ((-87.69916 41.98312, -87.69915 41.982...
7 8.0 58.0 2022-06-01 00:00:00.000 8.0 {2B5945BD-349C-4088-9B25-D99D4FB6C01D} 1.799926e+08 77255.568224 POLYGON ((-87.58587 41.76424, -87.58597 41.764...
37 38.0 88.0 2022-06-01 00:00:00.000 38.0 {6E5F0557-2DCA-490E-8E7D-C5B58CA65DFA} 1.775660e+08 91571.573668 POLYGON ((-87.75961 41.95327, -87.75964 41.953...
27 28.0 78.0 2022-06-01 00:00:00.000 28.0 {65BDECD2-AB03-4F1B-8025-49E3B1029A49} 1.600439e+08 129592.820270 POLYGON ((-87.72098 41.88802, -87.71974 41.888...
26 27.0 77.0 2022-06-01 00:00:00.000 27.0 {5EFBE372-72FB-4702-8C3C-BA882825EEF1} 1.595750e+08 129446.885360 POLYGON ((-87.63420 41.89660, -87.63426 41.896...
12 13.0 63.0 2022-06-01 00:00:00.000 13.0 {883D9536-9DDE-4FB8-B340-E9A644FD1851} 1.480001e+08 59975.600111 POLYGON ((-87.74205 41.77113, -87.74206 41.771...
19 20.0 70.0 2022-06-01 00:00:00.000 20.0 {1EA93731-81AC-42D6-9711-283C3A3CA2BE} 1.453499e+08 100221.251179 POLYGON ((-87.62082 41.79383, -87.62050 41.793...
6 7.0 57.0 2022-06-01 00:00:00.000 7.0 {279FCBD9-EA0D-4FFC-A8CA-EDA2676C0721} 1.414924e+08 98906.567862 POLYGON ((-87.54393 41.76030, -87.54370 41.760...
44 45.0 95.0 2022-06-01 00:00:00.000 45.0 {18480250-3E08-4D68-BF2E-96E27F6503B5} 1.394346e+08 117115.300022 POLYGON ((-87.77310 42.01148, -87.77309 42.011...
5 6.0 56.0 2022-06-01 00:00:00.000 6.0 {FD74A999-4BBA-4CE3-BEBB-CC76423037E8} 1.392022e+08 80779.851890 POLYGON ((-87.61794 41.77292, -87.61786 41.772...
11 12.0 62.0 2022-06-01 00:00:00.000 12.0 {EAD019CB-AA66-48C4-9338-795B4E083B59} 1.334616e+08 76139.484398 POLYGON ((-87.66588 41.84493, -87.66581 41.844...
16 17.0 67.0 2022-06-01 00:00:00.000 17.0 {A0475DAB-473E-447B-9F82-AEC0CA483C93} 1.301704e+08 90154.781522 POLYGON ((-87.65421 41.76869, -87.65421 41.768...
10 11.0 61.0 2022-06-01 00:00:00.000 11.0 {C7397C87-C4AE-4C48-A00E-50D2CD1100CF} 1.273484e+08 64972.869726 POLYGON ((-87.63600 41.81635, -87.63602 41.816...
15 16.0 66.0 2022-06-01 00:00:00.000 16.0 {B54690B6-21DF-44F5-B898-D73EF9976BDC} 1.258524e+08 90382.506038 POLYGON ((-87.64077 41.77616, -87.64082 41.776...
13 14.0 64.0 2022-06-01 00:00:00.000 14.0 {612295DC-E128-468C-B0C9-A1ADE1CB1C84} 1.213109e+08 72296.250663 POLYGON ((-87.69421 41.80828, -87.69420 41.808...
28 29.0 79.0 2022-06-01 00:00:00.000 29.0 {C1A9937E-2864-4CFB-ADD5-B8397C56DC77} 1.193660e+08 97816.079177 POLYGON ((-87.80127 41.93944, -87.80127 41.939...
22 23.0 73.0 2022-06-01 00:00:00.000 23.0 {51BB999E-306A-4091-8F7E-4241AACA3340} 1.168305e+08 94602.226753 POLYGON ((-87.71024 41.77156, -87.71039 41.771...
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876...
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766...
23 24.0 74.0 2022-06-01 00:00:00.000 24.0 {9ED052F7-F703-4A2D-A829-363FB60472C4} 1.120000e+08 68816.597232 POLYGON ((-87.69070 41.85635, -87.69077 41.856...
21 22.0 72.0 2022-06-01 00:00:00.000 22.0 {0705D4DE-80BF-473A-B3B7-078D63AD0298} 1.055096e+08 60413.987154 POLYGON ((-87.70761 41.84995, -87.70761 41.849...
36 37.0 87.0 2022-06-01 00:00:00.000 37.0 {35FCA85E-7EA3-4399-9077-7EACCF85268E} 1.004835e+08 56306.600969 POLYGON ((-87.72266 41.90316, -87.72266 41.903...
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865...
39 40.0 90.0 2022-06-01 00:00:00.000 40.0 {EA278E33-45CB-4D28-BEE1-F64C155E65B9} 9.664484e+07 67854.255079 POLYGON ((-87.68152 42.00812, -87.68144 42.007...
29 30.0 80.0 2022-06-01 00:00:00.000 30.0 {15C33223-51B6-456F-B790-BEC795885C33} 9.490456e+07 81414.586459 POLYGON ((-87.73242 41.95181, -87.73242 41.951...
24 25.0 75.0 2022-06-01 00:00:00.000 25.0 {B1A8F67E-3BEB-4E6A-967B-DB2271B162C5} 9.329780e+07 80678.887175 POLYGON ((-87.63901 41.86002, -87.63901 41.859...
31 32.0 82.0 2022-06-01 00:00:00.000 32.0 {2106D44D-07AC-4B39-A878-BEBB439D1BF3} 9.288828e+07 47973.924224 POLYGON ((-87.68097 41.94636, -87.68097 41.946...
46 47.0 97.0 2022-06-01 00:00:00.000 47.0 {4F17B913-08A1-4EF6-BF20-0EF4B6478494} 8.481029e+07 55157.008247 POLYGON ((-87.65979 41.97332, -87.65978 41.973...
35 36.0 86.0 2022-06-01 00:00:00.000 36.0 {337BAF17-7684-4F7F-BFCA-0BFD2B92B869} 8.383845e+07 118667.485047 POLYGON ((-87.76599 41.92398, -87.76591 41.923...
14 15.0 65.0 2022-06-01 00:00:00.000 15.0 {51F05987-1A65-4707-B17E-98C8709061B1} 8.307862e+07 107657.780595 POLYGON ((-87.63584 41.80905, -87.63585 41.809...
25 26.0 76.0 2022-06-01 00:00:00.000 26.0 {BB18C0C9-4A3A-43F8-A953-6A8B4D2487D5} 7.767961e+07 60930.848090 POLYGON ((-87.73649 41.92253, -87.73648 41.922...
34 35.0 85.0 2022-06-01 00:00:00.000 35.0 {3FDB81BF-D813-4AA7-9F92-DD74FD23B646} 7.613137e+07 70987.979595 POLYGON ((-87.69620 41.94670, -87.69620 41.946...
49 50.0 100.0 2022-06-01 00:00:00.000 50.0 {C4F10402-10E2-4401-BD4D-7FBDAF35E3FC} 7.450479e+07 60789.219509 POLYGON ((-87.68189 42.00896, -87.68204 42.008...
30 31.0 81.0 2022-06-01 00:00:00.000 31.0 {0E9C61BE-C5B1-4051-AB5C-833CB7887482} 7.442608e+07 52347.368005 POLYGON ((-87.72392 41.93913, -87.72371 41.939...
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928...
42 43.0 93.0 2022-06-01 00:00:00.000 43.0 {1003F8BC-CAE5-46E7-8A50-95CC5B60E8C7} 6.223707e+07 48459.476947 POLYGON ((-87.63183 41.93305, -87.63183 41.932...
32 33.0 83.0 2022-06-01 00:00:00.000 33.0 {F01E135A-54DB-49B2-867E-7F2DCD35A1F6} 6.217322e+07 48801.435311 POLYGON ((-87.70353 41.97186, -87.70344 41.971...
45 46.0 96.0 2022-06-01 00:00:00.000 46.0 {C894F602-BEBF-4984-803F-736F2BB8F6DE} 5.592727e+07 52699.506856 POLYGON ((-87.64521 41.96974, -87.64516 41.969...
41 42.0 92.0 2022-06-01 00:00:00.000 42.0 {AE139837-FCC1-4E2A-84A3-15B2B67D65A4} 5.253453e+07 68484.113474 POLYGON ((-87.62685 41.89668, -87.62685 41.896...
48 49.0 99.0 2022-06-01 00:00:00.000 49.0 {F7B2FFFC-D9B6-463F-BFF0-8C5C2ED72D47} 5.088363e+07 37398.359952 POLYGON ((-87.65729 42.00418, -87.65729 42.004...
43 44.0 94.0 2022-06-01 00:00:00.000 44.0 {E181C590-6E28-4CF9-85A1-96AF19075184} 4.750785e+07 36707.423435 POLYGON ((-87.65682 41.95140, -87.65681 41.951...
47 48.0 98.0 2022-06-01 00:00:00.000 48.0 {174DEC8E-5281-4774-831E-A7E0F6F3440D} 4.500890e+07 35618.125393 POLYGON ((-87.64430 41.96990, -87.64516 41.969...
33 34.0 84.0 2022-06-01 00:00:00.000 34.0 {54EBC7A4-FE32-4936-A72D-33A39D37248F} 4.272862e+07 75371.506020 POLYGON ((-87.63968 41.88906, -87.63924 41.887...
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904...
#map the wards. Based on my previous knowledge of Chicago, ward size is mainly based on population.
#ward shape is very irregular due to political motivations
WardBoundaries.plot(figsize=(14,12))
<Axes: >
_images/b0a4337790532ff18c4508c48e15110fd7afde1ff6ac789eb965b439de7c594c.png
#ensure the coordinate system is the same before joining the files. We must join the files to see crashes within each ward.
WardBoundaries.crs
<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World.
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich
TrafficCrashes.crs
<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World.
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich
#join ward to crashes so we can see what ward every crash is within
crashes_by_ward=geopandas.sjoin(TrafficCrashes,WardBoundaries[['ward','geometry']].copy(),predicate='within')
#preview the data to ensure the join operated as we anticipated it would
crashes_by_ward.head()
crash_reco date_crash time_crash posted_spe first_cras trafficway crash_type hit_and_ru damage prim_contr ... injuries_i injuries_n injuries_r injuries_2 injuries_u latitude longitude geometry index_right ward
0 367490fad73ad47e7c570928f719c506c645fbf2099e14... 2022-12-31 23:59:00.000 20.0 PARKED MOTOR VEHICLE ONE-WAY NO INJURY / DRIVE AWAY Y OVER $1,500 UNABLE TO DETERMINE ... 0.0 0.0 0.0 1.0 0.0 41.937900 -87.792173 POINT (-87.79217 41.93790) 35 36.0
73 4e472536a1fb6f72ffcc851db6795c29db404862d1b9a1... 2022-12-31 19:04:00.000 25.0 ANGLE FOUR WAY INJURY AND / OR TOW DUE TO CRASH Y OVER $1,500 UNABLE TO DETERMINE ... 0.0 1.0 0.0 2.0 0.0 41.936562 -87.787244 POINT (-87.78724 41.93656) 35 36.0
195 9b18219e9cf780d90b6fa9a54eb5800ca44ddfd0e361d2... 2022-12-31 11:25:00.000 25.0 REAR TO SIDE PARKING LOT NO INJURY / DRIVE AWAY None $501 - $1,500 UNABLE TO DETERMINE ... 0.0 0.0 0.0 2.0 0.0 41.911946 -87.736321 POINT (-87.73632 41.91195) 35 36.0
207 c804f78acd5c9ba0688d3f85f3eacc1fb6462696a8f178... 2022-12-31 09:50:00.000 30.0 TURNING NOT DIVIDED NO INJURY / DRIVE AWAY None OVER $1,500 IMPROPER TURNING/NO SIGNAL ... 0.0 0.0 0.0 2.0 0.0 41.923870 -87.766140 POINT (-87.76614 41.92387) 35 36.0
224 a3c8a19eab9b4d958c12394e462dfb2161dcc58df9f136... 2022-12-31 06:45:00.000 30.0 PEDALCYCLIST NOT DIVIDED INJURY AND / OR TOW DUE TO CRASH None $501 - $1,500 FAILING TO YIELD RIGHT-OF-WAY ... 0.0 0.0 1.0 1.0 0.0 41.907685 -87.729926 POINT (-87.72993 41.90768) 35 36.0

5 rows × 29 columns

#view a summary of how many crashes are in each ward and sort descending by crash number.
counts_per_ward=crashes_by_ward.groupby('ward',as_index=False).size()
counts_per_ward.rename(columns={"size":"number_of_crashes"},inplace=True)
counts_per_ward.sort_values(by='number_of_crashes',axis=0, ascending=False)
ward number_of_crashes
27 28.0 4611
26 27.0 4334
41 42.0 3886
5 6.0 3181
20 21.0 3146
7 8.0 2876
23 24.0 2664
36 37.0 2650
19 20.0 2505
15 16.0 2490
3 4.0 2488
16 17.0 2461
28 29.0 2413
13 14.0 2322
11 12.0 2300
17 18.0 2261
31 32.0 2228
33 34.0 2200
8 9.0 2129
35 36.0 2126
44 45.0 2114
24 25.0 2113
4 5.0 2101
22 23.0 2082
2 3.0 2058
1 2.0 2023
38 39.0 1934
30 31.0 1934
12 13.0 1889
21 22.0 1843
0 1.0 1815
18 19.0 1790
34 35.0 1772
29 30.0 1768
14 15.0 1762
40 41.0 1728
10 11.0 1702
6 7.0 1688
49 50.0 1685
37 38.0 1654
9 10.0 1629
39 40.0 1604
25 26.0 1568
46 47.0 1554
42 43.0 1453
43 44.0 1402
32 33.0 1395
47 48.0 1380
45 46.0 1349
48 49.0 1293

These results are very interesting. I took a look at the detailed maps of each ward ( https://www.chicago.gov/city/en/depts/dgs/supp_info/ward_maps.html ) and noticed that the top 3, which were far above the other wards, each contained large portions of the Eisenhower highway (I-290), Kennedy highway (I-90), and Dusable Lakeshore Drive (DLSD). In comparison, the bottom three wards are geographically smaller due to higher density of population and only 2 of the 3 had portions of DLSD, and they are typically not as congested sections.

#add this summary to the ward data so we have a simiplified file that lists the number of crashes in each ward with the ward shapefile information. Preview the data.
Wards = WardBoundaries.merge(counts_per_ward, on='ward')
Wards.head()
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry number_of_crashes
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928... 1815
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904... 2023
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865... 2058
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876... 2488
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766... 2101
#plot the data as a choropleth map to show the range of crashes and where there are the most.
ax=Wards.plot(column='number_of_crashes', figsize=(14,12),cmap='OrRd', legend=True)
_images/1022a0fc85d5f9ff9827f890235c1fe3e77b83d6b3eebd290c105ba84afbef9b.png
#The issue here is that the wards are all different sizes and we cannot exactly compare them one for one. 
#I am interested in this comparison to know density of crashes and be able to target wards that need political intervention.
#I will add a column that normalizes the crashes by area
Wards["crashes_per_area"]=Wards["number_of_crashes"] / Wards["st_area_sh"]
Wards.sort_values(by='crashes_per_area',ascending=False)
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry number_of_crashes crashes_per_area
41 42.0 92.0 2022-06-01 00:00:00.000 42.0 {AE139837-FCC1-4E2A-84A3-15B2B67D65A4} 5.253453e+07 68484.113474 POLYGON ((-87.62685 41.89668, -87.62685 41.896... 3886 0.000074
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904... 2023 0.000065
33 34.0 84.0 2022-06-01 00:00:00.000 34.0 {54EBC7A4-FE32-4936-A72D-33A39D37248F} 4.272862e+07 75371.506020 POLYGON ((-87.63968 41.88906, -87.63924 41.887... 2200 0.000051
47 48.0 98.0 2022-06-01 00:00:00.000 48.0 {174DEC8E-5281-4774-831E-A7E0F6F3440D} 4.500890e+07 35618.125393 POLYGON ((-87.64430 41.96990, -87.64516 41.969... 1380 0.000031
43 44.0 94.0 2022-06-01 00:00:00.000 44.0 {E181C590-6E28-4CF9-85A1-96AF19075184} 4.750785e+07 36707.423435 POLYGON ((-87.65682 41.95140, -87.65681 41.951... 1402 0.000030
27 28.0 78.0 2022-06-01 00:00:00.000 28.0 {65BDECD2-AB03-4F1B-8025-49E3B1029A49} 1.600439e+08 129592.820270 POLYGON ((-87.72098 41.88802, -87.71974 41.888... 4611 0.000029
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928... 1815 0.000028
26 27.0 77.0 2022-06-01 00:00:00.000 27.0 {5EFBE372-72FB-4702-8C3C-BA882825EEF1} 1.595750e+08 129446.885360 POLYGON ((-87.63420 41.89660, -87.63426 41.896... 4334 0.000027
36 37.0 87.0 2022-06-01 00:00:00.000 37.0 {35FCA85E-7EA3-4399-9077-7EACCF85268E} 1.004835e+08 56306.600969 POLYGON ((-87.72266 41.90316, -87.72266 41.903... 2650 0.000026
30 31.0 81.0 2022-06-01 00:00:00.000 31.0 {0E9C61BE-C5B1-4051-AB5C-833CB7887482} 7.442608e+07 52347.368005 POLYGON ((-87.72392 41.93913, -87.72371 41.939... 1934 0.000026
48 49.0 99.0 2022-06-01 00:00:00.000 49.0 {F7B2FFFC-D9B6-463F-BFF0-8C5C2ED72D47} 5.088363e+07 37398.359952 POLYGON ((-87.65729 42.00418, -87.65729 42.004... 1293 0.000025
35 36.0 86.0 2022-06-01 00:00:00.000 36.0 {337BAF17-7684-4F7F-BFCA-0BFD2B92B869} 8.383845e+07 118667.485047 POLYGON ((-87.76599 41.92398, -87.76591 41.923... 2126 0.000025
45 46.0 96.0 2022-06-01 00:00:00.000 46.0 {C894F602-BEBF-4984-803F-736F2BB8F6DE} 5.592727e+07 52699.506856 POLYGON ((-87.64521 41.96974, -87.64516 41.969... 1349 0.000024
31 32.0 82.0 2022-06-01 00:00:00.000 32.0 {2106D44D-07AC-4B39-A878-BEBB439D1BF3} 9.288828e+07 47973.924224 POLYGON ((-87.68097 41.94636, -87.68097 41.946... 2228 0.000024
23 24.0 74.0 2022-06-01 00:00:00.000 24.0 {9ED052F7-F703-4A2D-A829-363FB60472C4} 1.120000e+08 68816.597232 POLYGON ((-87.69070 41.85635, -87.69077 41.856... 2664 0.000024
42 43.0 93.0 2022-06-01 00:00:00.000 43.0 {1003F8BC-CAE5-46E7-8A50-95CC5B60E8C7} 6.223707e+07 48459.476947 POLYGON ((-87.63183 41.93305, -87.63183 41.932... 1453 0.000023
34 35.0 85.0 2022-06-01 00:00:00.000 35.0 {3FDB81BF-D813-4AA7-9F92-DD74FD23B646} 7.613137e+07 70987.979595 POLYGON ((-87.69620 41.94670, -87.69620 41.946... 1772 0.000023
5 6.0 56.0 2022-06-01 00:00:00.000 6.0 {FD74A999-4BBA-4CE3-BEBB-CC76423037E8} 1.392022e+08 80779.851890 POLYGON ((-87.61794 41.77292, -87.61786 41.772... 3181 0.000023
24 25.0 75.0 2022-06-01 00:00:00.000 25.0 {B1A8F67E-3BEB-4E6A-967B-DB2271B162C5} 9.329780e+07 80678.887175 POLYGON ((-87.63901 41.86002, -87.63901 41.859... 2113 0.000023
49 50.0 100.0 2022-06-01 00:00:00.000 50.0 {C4F10402-10E2-4401-BD4D-7FBDAF35E3FC} 7.450479e+07 60789.219509 POLYGON ((-87.68189 42.00896, -87.68204 42.008... 1685 0.000023
32 33.0 83.0 2022-06-01 00:00:00.000 33.0 {F01E135A-54DB-49B2-867E-7F2DCD35A1F6} 6.217322e+07 48801.435311 POLYGON ((-87.70353 41.97186, -87.70344 41.971... 1395 0.000022
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876... 2488 0.000021
14 15.0 65.0 2022-06-01 00:00:00.000 15.0 {51F05987-1A65-4707-B17E-98C8709061B1} 8.307862e+07 107657.780595 POLYGON ((-87.63584 41.80905, -87.63585 41.809... 1762 0.000021
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865... 2058 0.000021
28 29.0 79.0 2022-06-01 00:00:00.000 29.0 {C1A9937E-2864-4CFB-ADD5-B8397C56DC77} 1.193660e+08 97816.079177 POLYGON ((-87.80127 41.93944, -87.80127 41.939... 2413 0.000020
25 26.0 76.0 2022-06-01 00:00:00.000 26.0 {BB18C0C9-4A3A-43F8-A953-6A8B4D2487D5} 7.767961e+07 60930.848090 POLYGON ((-87.73649 41.92253, -87.73648 41.922... 1568 0.000020
15 16.0 66.0 2022-06-01 00:00:00.000 16.0 {B54690B6-21DF-44F5-B898-D73EF9976BDC} 1.258524e+08 90382.506038 POLYGON ((-87.64077 41.77616, -87.64082 41.776... 2490 0.000020
13 14.0 64.0 2022-06-01 00:00:00.000 14.0 {612295DC-E128-468C-B0C9-A1ADE1CB1C84} 1.213109e+08 72296.250663 POLYGON ((-87.69421 41.80828, -87.69420 41.808... 2322 0.000019
16 17.0 67.0 2022-06-01 00:00:00.000 17.0 {A0475DAB-473E-447B-9F82-AEC0CA483C93} 1.301704e+08 90154.781522 POLYGON ((-87.65421 41.76869, -87.65421 41.768... 2461 0.000019
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766... 2101 0.000019
29 30.0 80.0 2022-06-01 00:00:00.000 30.0 {15C33223-51B6-456F-B790-BEC795885C33} 9.490456e+07 81414.586459 POLYGON ((-87.73242 41.95181, -87.73242 41.951... 1768 0.000019
46 47.0 97.0 2022-06-01 00:00:00.000 47.0 {4F17B913-08A1-4EF6-BF20-0EF4B6478494} 8.481029e+07 55157.008247 POLYGON ((-87.65979 41.97332, -87.65978 41.973... 1554 0.000018
22 23.0 73.0 2022-06-01 00:00:00.000 23.0 {51BB999E-306A-4091-8F7E-4241AACA3340} 1.168305e+08 94602.226753 POLYGON ((-87.71024 41.77156, -87.71039 41.771... 2082 0.000018
21 22.0 72.0 2022-06-01 00:00:00.000 22.0 {0705D4DE-80BF-473A-B3B7-078D63AD0298} 1.055096e+08 60413.987154 POLYGON ((-87.70761 41.84995, -87.70761 41.849... 1843 0.000017
19 20.0 70.0 2022-06-01 00:00:00.000 20.0 {1EA93731-81AC-42D6-9711-283C3A3CA2BE} 1.453499e+08 100221.251179 POLYGON ((-87.62082 41.79383, -87.62050 41.793... 2505 0.000017
11 12.0 62.0 2022-06-01 00:00:00.000 12.0 {EAD019CB-AA66-48C4-9338-795B4E083B59} 1.334616e+08 76139.484398 POLYGON ((-87.66588 41.84493, -87.66581 41.844... 2300 0.000017
39 40.0 90.0 2022-06-01 00:00:00.000 40.0 {EA278E33-45CB-4D28-BEE1-F64C155E65B9} 9.664484e+07 67854.255079 POLYGON ((-87.68152 42.00812, -87.68144 42.007... 1604 0.000017
7 8.0 58.0 2022-06-01 00:00:00.000 8.0 {2B5945BD-349C-4088-9B25-D99D4FB6C01D} 1.799926e+08 77255.568224 POLYGON ((-87.58587 41.76424, -87.58597 41.764... 2876 0.000016
44 45.0 95.0 2022-06-01 00:00:00.000 45.0 {18480250-3E08-4D68-BF2E-96E27F6503B5} 1.394346e+08 117115.300022 POLYGON ((-87.77310 42.01148, -87.77309 42.011... 2114 0.000015
20 21.0 71.0 2022-06-01 00:00:00.000 21.0 {BA7C81E8-7DEB-46DF-8E71-95F9AE112FF3} 2.118767e+08 92642.006031 POLYGON ((-87.62405 41.73014, -87.62410 41.730... 3146 0.000015
10 11.0 61.0 2022-06-01 00:00:00.000 11.0 {C7397C87-C4AE-4C48-A00E-50D2CD1100CF} 1.273484e+08 64972.869726 POLYGON ((-87.63600 41.81635, -87.63602 41.816... 1702 0.000013
12 13.0 63.0 2022-06-01 00:00:00.000 13.0 {883D9536-9DDE-4FB8-B340-E9A644FD1851} 1.480001e+08 59975.600111 POLYGON ((-87.74205 41.77113, -87.74206 41.771... 1889 0.000013
6 7.0 57.0 2022-06-01 00:00:00.000 7.0 {279FCBD9-EA0D-4FFC-A8CA-EDA2676C0721} 1.414924e+08 98906.567862 POLYGON ((-87.54393 41.76030, -87.54370 41.760... 1688 0.000012
17 18.0 68.0 2022-06-01 00:00:00.000 18.0 {E22B6995-91F8-4C49-A9F3-4085D503F2A4} 1.933789e+08 79337.751930 POLYGON ((-87.65830 41.73950, -87.65834 41.739... 2261 0.000012
38 39.0 89.0 2022-06-01 00:00:00.000 39.0 {15480A27-2480-40CF-91EC-72B090F03522} 1.818672e+08 77704.757487 POLYGON ((-87.69916 41.98312, -87.69915 41.982... 1934 0.000011
37 38.0 88.0 2022-06-01 00:00:00.000 38.0 {6E5F0557-2DCA-490E-8E7D-C5B58CA65DFA} 1.775660e+08 91571.573668 POLYGON ((-87.75961 41.95327, -87.75964 41.953... 1654 0.000009
8 9.0 59.0 2022-06-01 00:00:00.000 9.0 {B75B90E6-CB95-4890-BBC3-D2F313E2EE80} 2.344895e+08 102227.294779 POLYGON ((-87.61414 41.72189, -87.61414 41.721... 2129 0.000009
18 19.0 69.0 2022-06-01 00:00:00.000 19.0 {91001AF5-B4E0-4F45-A1CB-7C22070BA22D} 2.199899e+08 101405.125517 POLYGON ((-87.66674 41.73022, -87.66677 41.730... 1790 0.000008
40 41.0 91.0 2022-06-01 00:00:00.000 41.0 {C885247A-E064-4FCF-A35A-747DEC142421} 4.754967e+08 218605.417697 POLYGON ((-87.79065 42.00040, -87.79058 42.000... 1728 0.000004
9 10.0 60.0 2022-06-01 00:00:00.000 10.0 {19FF2026-6DDD-45DA-8DF6-B44B0C15834C} 5.773395e+08 147455.404991 POLYGON ((-87.53018 41.74310, -87.53008 41.742... 1629 0.000003
#Lets see the difference
ax=Wards.plot(column='crashes_per_area', figsize=(14,12),cmap='OrRd', legend=True)
_images/55a66f5a2404c923e9e1701b796e57c4ff0957447b1506f35c5eb495c2e45ceb.png
#add more details to the map.
f, ax = plt.subplots(1, figsize=(14,12))
ax = Wards.plot(column='crashes_per_area', cmap='OrRd', legend=True, ax=ax)
lims = plt.axis('equal')
ax.set_title('Wards near Loop, Eisenhower (I-290), and I-94 Split experience highest density of vehicular crashes', weight='black', size=20)
plt.show()
_images/2ee09d9c12aacb593d400d807b41cac9d7ad1aebf5bbb2fcdecc126d6b48ceee.png
#Now that we know what wards in Chicago have the most crashes, we can look into one of the tactics the city implements to improve safety and decrease crashes. 
#This tactic is the implementation of speed cameras.
SpeedCam = 'Speed_Camera_Locations.csv'
if os.path.exists(SpeedCam):
    print('SpeedCam:', SpeedCam)
else:
    print('Please download the tutorial data or fix the path!')
SpeedCam: Speed_Camera_Locations.csv
#read file and check coordinate system
SpeedCam1 = geopandas.read_file(SpeedCam)
crs = {'init':'epsg:4326'}
#since this file was a csv, I need to convert the latitude and longitude data to be recognized geospatially. I do this with a geodataframe and the geopandas library.
#the file has a latitude and a longitude column that I can utilize to add a geometry column. I ensure that the coordinate system selected will match the rest of my data.
gspeedcam = geopandas.GeoDataFrame(
    SpeedCam1, geometry=geopandas.points_from_xy(SpeedCam1.LONGITUDE, SpeedCam1.LATITUDE), crs="EPSG:4326")
gspeedcam.head()
ADDRESS FIRST APPROACH SECOND APPROACH GO-LIVE DATE LATITUDE LONGITUDE LOCATION geometry
0 4949 W Lawrence Ave (Speed Camera) EB WB 03/22/2023 41.9679 -87.7523 (41.9679,-87.7523) POINT (-87.75230 41.96790)
1 7508 W Touhy Ave(Speed Camera) EB WB 03/02/2023 42.011548085311354 -87.81442004192668 (42.011548085311354, -87.81442004192668) POINT (-87.81442 42.01155)
2 6523 N Western (Speed Camera) NB SB 11/10/2013 42.00025951144952 -87.68980290863908 (42.00025951144952, -87.68980290863908) POINT (-87.68980 42.00026)
3 6125 N Cicero Ave (Speed Camera) NB SB 03/17/2014 41.9921194114274 -87.74847678515228 (41.9921194114274, -87.74847678515228) POINT (-87.74848 41.99212)
4 3137 W Peterson (Speed Camera) EB WB 01/03/2014 41.9902819135942 -87.7095 (41.9902819135942, -87.7095) POINT (-87.70950 41.99028)
#We are going to join the speed camera location data with the ward boundaries data to see what ward each camera is located in.
Speedcam_crashes_by_ward=geopandas.sjoin(gspeedcam,WardBoundaries[['ward','geometry']].copy(),predicate='within')
Speedcam_crashes_by_ward.head()
ADDRESS FIRST APPROACH SECOND APPROACH GO-LIVE DATE LATITUDE LONGITUDE LOCATION geometry index_right ward
0 4949 W Lawrence Ave (Speed Camera) EB WB 03/22/2023 41.9679 -87.7523 (41.9679,-87.7523) POINT (-87.75230 41.96790) 44 45.0
10 6020 W Foster Ave (Speed Camera) WB EB 03/10/2023 41.97568071224708 -87.7787773830256 (41.97568071224708, -87.7787773830256) POINT (-87.77878 41.97568) 44 45.0
14 5471 W Higgins (Speed Camera) EB WB 02/14/2014 41.96924714863934 -87.76401945149458 (41.96924714863934, -87.76401945149458) POINT (-87.76402 41.96925) 44 45.0
15 5432 W Lawrence (Speed Camera) EB WB 02/14/2014 41.96785573012919 -87.76392864369929 (41.96785573012919, -87.76392864369929) POINT (-87.76393 41.96786) 44 45.0
1 7508 W Touhy Ave(Speed Camera) EB WB 03/02/2023 42.011548085311354 -87.81442004192668 (42.011548085311354, -87.81442004192668) POINT (-87.81442 42.01155) 40 41.0
#Looks like some of the speed cameras go-live date was after 2022. We will need to get rid of those since our crash date is for 2022.
#In order to filter by date we have to convert the column from an object to a date field.

Speedcam_crashes_by_ward.dtypes
ADDRESS              object
FIRST APPROACH       object
SECOND APPROACH      object
GO-LIVE DATE         object
LATITUDE             object
LONGITUDE            object
LOCATION             object
geometry           geometry
index_right           int64
ward                float64
dtype: object
Speedcam_crashes_by_ward["GO-LIVE DATE"]=pd.to_datetime(Speedcam_crashes_by_ward["GO-LIVE DATE"])
Speedcam_crashes_by_ward.head()
ADDRESS FIRST APPROACH SECOND APPROACH GO-LIVE DATE LATITUDE LONGITUDE LOCATION geometry index_right ward
0 4949 W Lawrence Ave (Speed Camera) EB WB 2023-03-22 41.9679 -87.7523 (41.9679,-87.7523) POINT (-87.75230 41.96790) 44 45.0
10 6020 W Foster Ave (Speed Camera) WB EB 2023-03-10 41.97568071224708 -87.7787773830256 (41.97568071224708, -87.7787773830256) POINT (-87.77878 41.97568) 44 45.0
14 5471 W Higgins (Speed Camera) EB WB 2014-02-14 41.96924714863934 -87.76401945149458 (41.96924714863934, -87.76401945149458) POINT (-87.76402 41.96925) 44 45.0
15 5432 W Lawrence (Speed Camera) EB WB 2014-02-14 41.96785573012919 -87.76392864369929 (41.96785573012919, -87.76392864369929) POINT (-87.76393 41.96786) 44 45.0
1 7508 W Touhy Ave(Speed Camera) EB WB 2023-03-02 42.011548085311354 -87.81442004192668 (42.011548085311354, -87.81442004192668) POINT (-87.81442 42.01155) 40 41.0
Speedcam_crashes_by_ward.dtypes
ADDRESS                    object
FIRST APPROACH             object
SECOND APPROACH            object
GO-LIVE DATE       datetime64[ns]
LATITUDE                   object
LONGITUDE                  object
LOCATION                   object
geometry                 geometry
index_right                 int64
ward                      float64
dtype: object
Speedcam_crashes_by_ward.sort_values(by='GO-LIVE DATE', ascending=False)
ADDRESS FIRST APPROACH SECOND APPROACH GO-LIVE DATE LATITUDE LONGITUDE LOCATION geometry index_right ward
142 4350 W 79th St (Speed Camera) WB 2023-05-19 41.749426144675795 -87.72979639455757 (41.749426144675795, -87.72979639455757) POINT (-87.72980 41.74943) 17 18.0
96 3314 W 16th St (Speed Camera) EB WB 2023-05-08 41.8591 -87.70866665927319 (41.8591, -87.70866665927319) POINT (-87.70867 41.85910) 23 24.0
100 3536 S Wallace St (Speed Camea) NB SB 2023-05-08 41.8297474389017 -87.641307410277 (41.8297474389017, -87.641307410277) POINT (-87.64131 41.82975) 10 11.0
144 1215 E 83RD ST (Speed Camera) EB WB 2023-05-05 41.7441 -87.5939 (41.7441, -87.5939) POINT (-87.59390 41.74410) 7 8.0
57 2223 N Kedzie Blvd (Speed Camera) NB SB 2023-05-02 41.9219894043721 -87.7070308742212 (41.9219894043721, -87.7070308742212) POINT (-87.70703 41.92199) 0 1.0
... ... ... ... ... ... ... ... ... ... ...
130 3450 W 71ST ST (Speed Camera) EB WB 2013-09-06 41.76439095689881 -87.70972841983624 (41.76439095689881, -87.70972841983624) POINT (-87.70973 41.76439) 16 17.0
126 6909 S Kedzie Ave (Speed Camera) NB 2013-09-06 41.76773186901884 -87.70273790708362 (41.76773186901884, -87.70273790708362) POINT (-87.70274 41.76773) 16 17.0
125 6818 S Kedzie Ave (Speed Camera) SB 2013-09-06 41.769106296454154 -87.70305895795853 (41.769106296454154, -87.70305895795853) POINT (-87.70306 41.76911) 16 17.0
11 4124 W Foster Ave (Speed Camera) EB WB 2013-08-26 41.975501 -87.73166979484374 (41.975501, -87.73166979484374) POINT (-87.73167 41.97550) 38 39.0
12 5120 N Pulaski Rd (Speed Camera) NB SB 2013-08-26 41.97433265461055 -87.728215 (41.97433265461055, -87.728215) POINT (-87.72822 41.97433) 38 39.0

161 rows × 10 columns

#We want to get rid of any cameras that were placed in 2022 or after because the crash data is only for 2022 and we want to look at the effects of the cameras that were there for the entire year.
Speedcam_crashes_by_ward=Speedcam_crashes_by_ward[(Speedcam_crashes_by_ward['GO-LIVE DATE'] < '2022-01-01')]
Speedcam_crashes_by_ward.sort_values(by='GO-LIVE DATE', ascending=False)
ADDRESS FIRST APPROACH SECOND APPROACH GO-LIVE DATE LATITUDE LONGITUDE LOCATION geometry index_right ward
135 1330 W 76th St(Speed Camera) EB WB 2021-07-09 41.75604940593661 -87.65705959049882 (41.75604940593661, -87.65705959049882) POINT (-87.65706 41.75605) 16 17.0
67 1444 W Division St(Speed Camera) WB 2018-09-05 41.903482 -87.664378 (41.903482, -87.664378) POINT (-87.66438 41.90348) 0 1.0
68 1455 W Division St(Speed Camera) EB 2018-09-05 41.90329 -87.664873 (41.90329, -87.664873) POINT (-87.66487 41.90329) 26 27.0
102 4246 W 47th St(Speed Camera) WB 2018-08-27 41.807853 -87.730128 (41.807853, -87.730128) POINT (-87.73013 41.80785) 13 14.0
103 4319 W 47th St(Speed Camera) EB 2018-08-27 41.807645 -87.731753 (41.807645, -87.731753) POINT (-87.73175 41.80765) 13 14.0
... ... ... ... ... ... ... ... ... ... ...
125 6818 S Kedzie Ave (Speed Camera) SB 2013-09-06 41.769106296454154 -87.70305895795853 (41.769106296454154, -87.70305895795853) POINT (-87.70306 41.76911) 16 17.0
130 3450 W 71ST ST (Speed Camera) EB WB 2013-09-06 41.76439095689881 -87.70972841983624 (41.76439095689881, -87.70972841983624) POINT (-87.70973 41.76439) 16 17.0
126 6909 S Kedzie Ave (Speed Camera) NB 2013-09-06 41.76773186901884 -87.70273790708362 (41.76773186901884, -87.70273790708362) POINT (-87.70274 41.76773) 16 17.0
11 4124 W Foster Ave (Speed Camera) EB WB 2013-08-26 41.975501 -87.73166979484374 (41.975501, -87.73166979484374) POINT (-87.73167 41.97550) 38 39.0
12 5120 N Pulaski Rd (Speed Camera) NB SB 2013-08-26 41.97433265461055 -87.728215 (41.97433265461055, -87.728215) POINT (-87.72822 41.97433) 38 39.0

146 rows × 10 columns

#This removed 15 rows! These speed cameras were likely in different locations before 2022 and could have an effect on the results.
#Map the speed cameras and utilize the crash choropleth map as a basemap. This will help me see if speed cameras are located in areas with more crashes.
base=Wards.plot(figsize=(14,12), column='crashes_per_area', cmap='OrRd', linewidth=2, legend=True)
Speedcam_crashes_by_ward.plot(ax=base,figsize=(14,12),marker='P', color='blue', markersize=20, edgecolor='ghostwhite')
<Axes: >
_images/37f9397ea0f89089eb70d56cacc4d18996faa9eb5b3ac3c54ae076870f1f4de3.png
#We are now going to summarize this data to see how many speed cameras are in each ward and sort descending by number of cameras.
Wards.ward = Wards.ward.astype('float64').astype(str)
speedcam_counts_per_ward=Speedcam_crashes_by_ward.groupby('ward',as_index=False).size()
speedcam_counts_per_ward.rename(columns={"size":"cameras"},inplace=True)
speedcam_counts_per_ward.ward = speedcam_counts_per_ward.ward.astype('float64').astype(str)
speedcam_counts_per_ward.sort_values(by='cameras')
ward cameras
19 25.0 1
34 41.0 1
33 40.0 1
16 21.0 1
11 16.0 1
8 12.0 1
7 11.0 1
39 48.0 1
5 9.0 2
36 45.0 2
4 8.0 2
1 4.0 2
28 35.0 2
27 33.0 2
17 23.0 2
21 27.0 2
37 46.0 3
2 5.0 3
30 37.0 3
25 31.0 3
23 29.0 3
0 1.0 3
3 6.0 3
18 24.0 4
14 19.0 4
6 10.0 4
15 20.0 5
29 36.0 5
12 17.0 5
35 42.0 5
10 15.0 5
24 30.0 5
38 47.0 5
22 28.0 6
20 26.0 6
31 38.0 7
26 32.0 8
32 39.0 8
9 14.0 9
13 18.0 10
#join this summarized data with the Wards data so we can compare side by side. Replace NAN with zero (0) for wards without any cameras.
Wards=Wards.merge(speedcam_counts_per_ward, on='ward', how='left')
Wards=Wards.fillna(0)
Wards.head()
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry number_of_crashes crashes_per_area cameras
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928... 1815 0.000028 3.0
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904... 2023 0.000065 0.0
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865... 2058 0.000021 0.0
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876... 2488 0.000021 2.0
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766... 2101 0.000019 3.0
speedcammean=Wards["cameras"].mean()
speedcammedian =Wards["cameras"].median()
print("The average ward has %s speed cameras. The median number of speed cameras is %s" % (speedcammean, speedcammedian))
The average ward has 2.92 speed cameras. The median number of speed cameras is 2.0
Wards.sort_values(by='cameras', ascending=False)
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry number_of_crashes crashes_per_area cameras
17 18.0 68.0 2022-06-01 00:00:00.000 18.0 {E22B6995-91F8-4C49-A9F3-4085D503F2A4} 1.933789e+08 79337.751930 POLYGON ((-87.65830 41.73950, -87.65834 41.739... 2261 0.000012 10.0
13 14.0 64.0 2022-06-01 00:00:00.000 14.0 {612295DC-E128-468C-B0C9-A1ADE1CB1C84} 1.213109e+08 72296.250663 POLYGON ((-87.69421 41.80828, -87.69420 41.808... 2322 0.000019 9.0
31 32.0 82.0 2022-06-01 00:00:00.000 32.0 {2106D44D-07AC-4B39-A878-BEBB439D1BF3} 9.288828e+07 47973.924224 POLYGON ((-87.68097 41.94636, -87.68097 41.946... 2228 0.000024 8.0
38 39.0 89.0 2022-06-01 00:00:00.000 39.0 {15480A27-2480-40CF-91EC-72B090F03522} 1.818672e+08 77704.757487 POLYGON ((-87.69916 41.98312, -87.69915 41.982... 1934 0.000011 8.0
37 38.0 88.0 2022-06-01 00:00:00.000 38.0 {6E5F0557-2DCA-490E-8E7D-C5B58CA65DFA} 1.775660e+08 91571.573668 POLYGON ((-87.75961 41.95327, -87.75964 41.953... 1654 0.000009 7.0
25 26.0 76.0 2022-06-01 00:00:00.000 26.0 {BB18C0C9-4A3A-43F8-A953-6A8B4D2487D5} 7.767961e+07 60930.848090 POLYGON ((-87.73649 41.92253, -87.73648 41.922... 1568 0.000020 6.0
27 28.0 78.0 2022-06-01 00:00:00.000 28.0 {65BDECD2-AB03-4F1B-8025-49E3B1029A49} 1.600439e+08 129592.820270 POLYGON ((-87.72098 41.88802, -87.71974 41.888... 4611 0.000029 6.0
41 42.0 92.0 2022-06-01 00:00:00.000 42.0 {AE139837-FCC1-4E2A-84A3-15B2B67D65A4} 5.253453e+07 68484.113474 POLYGON ((-87.62685 41.89668, -87.62685 41.896... 3886 0.000074 5.0
35 36.0 86.0 2022-06-01 00:00:00.000 36.0 {337BAF17-7684-4F7F-BFCA-0BFD2B92B869} 8.383845e+07 118667.485047 POLYGON ((-87.76599 41.92398, -87.76591 41.923... 2126 0.000025 5.0
29 30.0 80.0 2022-06-01 00:00:00.000 30.0 {15C33223-51B6-456F-B790-BEC795885C33} 9.490456e+07 81414.586459 POLYGON ((-87.73242 41.95181, -87.73242 41.951... 1768 0.000019 5.0
14 15.0 65.0 2022-06-01 00:00:00.000 15.0 {51F05987-1A65-4707-B17E-98C8709061B1} 8.307862e+07 107657.780595 POLYGON ((-87.63584 41.80905, -87.63585 41.809... 1762 0.000021 5.0
16 17.0 67.0 2022-06-01 00:00:00.000 17.0 {A0475DAB-473E-447B-9F82-AEC0CA483C93} 1.301704e+08 90154.781522 POLYGON ((-87.65421 41.76869, -87.65421 41.768... 2461 0.000019 5.0
46 47.0 97.0 2022-06-01 00:00:00.000 47.0 {4F17B913-08A1-4EF6-BF20-0EF4B6478494} 8.481029e+07 55157.008247 POLYGON ((-87.65979 41.97332, -87.65978 41.973... 1554 0.000018 5.0
19 20.0 70.0 2022-06-01 00:00:00.000 20.0 {1EA93731-81AC-42D6-9711-283C3A3CA2BE} 1.453499e+08 100221.251179 POLYGON ((-87.62082 41.79383, -87.62050 41.793... 2505 0.000017 5.0
9 10.0 60.0 2022-06-01 00:00:00.000 10.0 {19FF2026-6DDD-45DA-8DF6-B44B0C15834C} 5.773395e+08 147455.404991 POLYGON ((-87.53018 41.74310, -87.53008 41.742... 1629 0.000003 4.0
23 24.0 74.0 2022-06-01 00:00:00.000 24.0 {9ED052F7-F703-4A2D-A829-363FB60472C4} 1.120000e+08 68816.597232 POLYGON ((-87.69070 41.85635, -87.69077 41.856... 2664 0.000024 4.0
18 19.0 69.0 2022-06-01 00:00:00.000 19.0 {91001AF5-B4E0-4F45-A1CB-7C22070BA22D} 2.199899e+08 101405.125517 POLYGON ((-87.66674 41.73022, -87.66677 41.730... 1790 0.000008 4.0
36 37.0 87.0 2022-06-01 00:00:00.000 37.0 {35FCA85E-7EA3-4399-9077-7EACCF85268E} 1.004835e+08 56306.600969 POLYGON ((-87.72266 41.90316, -87.72266 41.903... 2650 0.000026 3.0
30 31.0 81.0 2022-06-01 00:00:00.000 31.0 {0E9C61BE-C5B1-4051-AB5C-833CB7887482} 7.442608e+07 52347.368005 POLYGON ((-87.72392 41.93913, -87.72371 41.939... 1934 0.000026 3.0
45 46.0 96.0 2022-06-01 00:00:00.000 46.0 {C894F602-BEBF-4984-803F-736F2BB8F6DE} 5.592727e+07 52699.506856 POLYGON ((-87.64521 41.96974, -87.64516 41.969... 1349 0.000024 3.0
28 29.0 79.0 2022-06-01 00:00:00.000 29.0 {C1A9937E-2864-4CFB-ADD5-B8397C56DC77} 1.193660e+08 97816.079177 POLYGON ((-87.80127 41.93944, -87.80127 41.939... 2413 0.000020 3.0
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928... 1815 0.000028 3.0
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766... 2101 0.000019 3.0
5 6.0 56.0 2022-06-01 00:00:00.000 6.0 {FD74A999-4BBA-4CE3-BEBB-CC76423037E8} 1.392022e+08 80779.851890 POLYGON ((-87.61794 41.77292, -87.61786 41.772... 3181 0.000023 3.0
22 23.0 73.0 2022-06-01 00:00:00.000 23.0 {51BB999E-306A-4091-8F7E-4241AACA3340} 1.168305e+08 94602.226753 POLYGON ((-87.71024 41.77156, -87.71039 41.771... 2082 0.000018 2.0
32 33.0 83.0 2022-06-01 00:00:00.000 33.0 {F01E135A-54DB-49B2-867E-7F2DCD35A1F6} 6.217322e+07 48801.435311 POLYGON ((-87.70353 41.97186, -87.70344 41.971... 1395 0.000022 2.0
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876... 2488 0.000021 2.0
44 45.0 95.0 2022-06-01 00:00:00.000 45.0 {18480250-3E08-4D68-BF2E-96E27F6503B5} 1.394346e+08 117115.300022 POLYGON ((-87.77310 42.01148, -87.77309 42.011... 2114 0.000015 2.0
8 9.0 59.0 2022-06-01 00:00:00.000 9.0 {B75B90E6-CB95-4890-BBC3-D2F313E2EE80} 2.344895e+08 102227.294779 POLYGON ((-87.61414 41.72189, -87.61414 41.721... 2129 0.000009 2.0
34 35.0 85.0 2022-06-01 00:00:00.000 35.0 {3FDB81BF-D813-4AA7-9F92-DD74FD23B646} 7.613137e+07 70987.979595 POLYGON ((-87.69620 41.94670, -87.69620 41.946... 1772 0.000023 2.0
7 8.0 58.0 2022-06-01 00:00:00.000 8.0 {2B5945BD-349C-4088-9B25-D99D4FB6C01D} 1.799926e+08 77255.568224 POLYGON ((-87.58587 41.76424, -87.58597 41.764... 2876 0.000016 2.0
26 27.0 77.0 2022-06-01 00:00:00.000 27.0 {5EFBE372-72FB-4702-8C3C-BA882825EEF1} 1.595750e+08 129446.885360 POLYGON ((-87.63420 41.89660, -87.63426 41.896... 4334 0.000027 2.0
10 11.0 61.0 2022-06-01 00:00:00.000 11.0 {C7397C87-C4AE-4C48-A00E-50D2CD1100CF} 1.273484e+08 64972.869726 POLYGON ((-87.63600 41.81635, -87.63602 41.816... 1702 0.000013 1.0
20 21.0 71.0 2022-06-01 00:00:00.000 21.0 {BA7C81E8-7DEB-46DF-8E71-95F9AE112FF3} 2.118767e+08 92642.006031 POLYGON ((-87.62405 41.73014, -87.62410 41.730... 3146 0.000015 1.0
47 48.0 98.0 2022-06-01 00:00:00.000 48.0 {174DEC8E-5281-4774-831E-A7E0F6F3440D} 4.500890e+07 35618.125393 POLYGON ((-87.64430 41.96990, -87.64516 41.969... 1380 0.000031 1.0
24 25.0 75.0 2022-06-01 00:00:00.000 25.0 {B1A8F67E-3BEB-4E6A-967B-DB2271B162C5} 9.329780e+07 80678.887175 POLYGON ((-87.63901 41.86002, -87.63901 41.859... 2113 0.000023 1.0
11 12.0 62.0 2022-06-01 00:00:00.000 12.0 {EAD019CB-AA66-48C4-9338-795B4E083B59} 1.334616e+08 76139.484398 POLYGON ((-87.66588 41.84493, -87.66581 41.844... 2300 0.000017 1.0
39 40.0 90.0 2022-06-01 00:00:00.000 40.0 {EA278E33-45CB-4D28-BEE1-F64C155E65B9} 9.664484e+07 67854.255079 POLYGON ((-87.68152 42.00812, -87.68144 42.007... 1604 0.000017 1.0
40 41.0 91.0 2022-06-01 00:00:00.000 41.0 {C885247A-E064-4FCF-A35A-747DEC142421} 4.754967e+08 218605.417697 POLYGON ((-87.79065 42.00040, -87.79058 42.000... 1728 0.000004 1.0
15 16.0 66.0 2022-06-01 00:00:00.000 16.0 {B54690B6-21DF-44F5-B898-D73EF9976BDC} 1.258524e+08 90382.506038 POLYGON ((-87.64077 41.77616, -87.64082 41.776... 2490 0.000020 1.0
6 7.0 57.0 2022-06-01 00:00:00.000 7.0 {279FCBD9-EA0D-4FFC-A8CA-EDA2676C0721} 1.414924e+08 98906.567862 POLYGON ((-87.54393 41.76030, -87.54370 41.760... 1688 0.000012 0.0
21 22.0 72.0 2022-06-01 00:00:00.000 22.0 {0705D4DE-80BF-473A-B3B7-078D63AD0298} 1.055096e+08 60413.987154 POLYGON ((-87.70761 41.84995, -87.70761 41.849... 1843 0.000017 0.0
42 43.0 93.0 2022-06-01 00:00:00.000 43.0 {1003F8BC-CAE5-46E7-8A50-95CC5B60E8C7} 6.223707e+07 48459.476947 POLYGON ((-87.63183 41.93305, -87.63183 41.932... 1453 0.000023 0.0
43 44.0 94.0 2022-06-01 00:00:00.000 44.0 {E181C590-6E28-4CF9-85A1-96AF19075184} 4.750785e+07 36707.423435 POLYGON ((-87.65682 41.95140, -87.65681 41.951... 1402 0.000030 0.0
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904... 2023 0.000065 0.0
12 13.0 63.0 2022-06-01 00:00:00.000 13.0 {883D9536-9DDE-4FB8-B340-E9A644FD1851} 1.480001e+08 59975.600111 POLYGON ((-87.74205 41.77113, -87.74206 41.771... 1889 0.000013 0.0
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865... 2058 0.000021 0.0
33 34.0 84.0 2022-06-01 00:00:00.000 34.0 {54EBC7A4-FE32-4936-A72D-33A39D37248F} 4.272862e+07 75371.506020 POLYGON ((-87.63968 41.88906, -87.63924 41.887... 2200 0.000051 0.0
48 49.0 99.0 2022-06-01 00:00:00.000 49.0 {F7B2FFFC-D9B6-463F-BFF0-8C5C2ED72D47} 5.088363e+07 37398.359952 POLYGON ((-87.65729 42.00418, -87.65729 42.004... 1293 0.000025 0.0
49 50.0 100.0 2022-06-01 00:00:00.000 50.0 {C4F10402-10E2-4401-BD4D-7FBDAF35E3FC} 7.450479e+07 60789.219509 POLYGON ((-87.68189 42.00896, -87.68204 42.008... 1685 0.000023 0.0
#Graphing the data to see the numbers side by side for each ward.
import numpy as np
import matplotlib.patches as mpatches

WardsChart=Wards.sort_values(['crashes_per_area'], ascending=False)

ax1=WardsChart.plot(x="ward", y="cameras", kind="bar",color='grey',position=0, width=0.3)
ax2 = WardsChart['crashes_per_area'].plot(secondary_y=True, color='navy',figsize=(50,20),kind='bar',position=1,width=0.3)
ax1.set_xlabel('Wards', fontdict={'fontsize': 40, 'fontweight': 'bold'})
ax1.set_ylabel('Cameras',fontdict={'fontsize': 40, 'fontweight': 'bold'})
ax2.set_ylabel('Crash Density',fontdict={'fontsize': 40, 'fontweight': 'bold'})
ax1.tick_params(axis='both',labelsize=30)
ax1.set_xticklabels(ax1.get_xticks(), rotation = 0)
ax2.tick_params(axis='both',labelsize=30)

ax1.legend(['Speed Cameras'],fontsize=30, loc='best', bbox_to_anchor=(0.15, 1))
plt.legend(['Density of Crashes'],fontsize=30, bbox_to_anchor=(0.0156, .94))

plt.show()
_images/8298a46f9ae3d1089781ebbbe6518a0b767fe12f5a9dcd6c5081c337bb7df71d.png

Most wards have at least one (1) speed camera, and ten (10) do not (not shown in the list above due to how I joined the data). These ten (10) most likely did have speed cameras at some point during 2022, but moved locations since. Ward 18 is the sixth largest (geographically) ward, so it is not extremely surprising to see it having more speed cameras, but, it has the most at ten (10). Of the top ten (10) wards with the most cameras, none are in the top ten (10) geographically largest wards. Of the bottom ten (10) wards for cameras, two (2) are in the bottom ten (10) geograaphical sized wards. Looking at crashes, one ward in the top five (5) for speed cameras is in the bottom ten (10) for crashes, and no wards with zero (0) cameras are in the top ten (10) for crashes. It is important to note that speed cameras are not on highways so wards where the majority of crashes occur on highways are not helped by the current placement of speed cameras.

Looking at crash density, three (3) of the top ten (10) wards for highest density of crashes have zero (0) speed cameras. Only two (2) wards in the bottom ten (10) for crash density are also in the top ten (10) for speed cameras. It is important to think about the difference in number of cameras. The lowest amount is zero (0) and the highest is ten (10). This is a big range. Overall, this analysis is inconclusive on its own and will need further investigation.

#Analyzing the relationship between the two variables
x=Wards.cameras
y=Wards.crashes_per_area

plt.scatter(x,y)

z=np.polyfit(x, y, 1)
p = np.poly1d(z)
plt.plot(x,p(x),"r")
plt.xlabel("Speed Cameras")
plt.ylabel("Density of Crashes")

plt.show()
_images/bb8a03114f371bdad24a76dba7b916764dda1d2acb0b6316da257e5884c0fd92.png
#The chart above shows a very small relationship. Finding the correlation between the variables will help me understand how strong this is.

#Finding the covariance
covariance = np.cov(x, y)
print(covariance)

#Finding Pearson's correlation p-value
from scipy.stats import pearsonr
corr, _ = pearsonr(x,y)
print('Pearsons correlation: %.3f' % corr)

#Finding Spearmans correlation p-value, which is helpful for understanding nonlinear relationships
from scipy.stats import spearmanr
corr, _ = spearmanr(x, y)
print('Spearmans correlation: %.3f' % corr)
[[ 6.72816327e+00 -4.23426976e-06]
 [-4.23426976e-06  1.57822963e-10]]
Pearsons correlation: -0.130
Spearmans correlation: -0.104
#There is a very small, negative correlation between the variables. This is negligible correlation. Thus, the relationship of this data is statistically insignificant.
#let's see if this changes when we only look at speed related crashes.
print(TrafficCrashes.columns)
Index(['crash_reco', 'date_crash', 'time_crash', 'posted_spe', 'first_cras',
       'trafficway', 'crash_type', 'hit_and_ru', 'damage', 'prim_contr',
       'sec_contri', 'street_no', 'street_dir', 'street_nam', 'dooring_i',
       'num_units', 'most_sever', 'injuries_t', 'injuries_f', 'injuries_i',
       'injuries_n', 'injuries_r', 'injuries_2', 'injuries_u', 'latitude',
       'longitude', 'geometry'],
      dtype='object')
SpeedCrashes = TrafficCrashes[(TrafficCrashes['prim_contr']=='EXCEEDING SAFE SPEED FOR CONDITIONS') | (TrafficCrashes['prim_contr']=='FAILING TO REDUCE SPEED TO AVOID CRASH')]

speedcrashes_by_ward=geopandas.sjoin(SpeedCrashes,WardBoundaries[['ward','geometry']].copy(),predicate='within')
speedcounts_per_ward=speedcrashes_by_ward.groupby('ward',as_index=False).size()
speedcounts_per_ward.rename(columns={"size":"number_of_speedcrashes"},inplace=True)
speedcounts_per_ward.sort_values(by='number_of_speedcrashes',axis=0, ascending=False)
speedWards = WardBoundaries.merge(speedcounts_per_ward, on='ward')
speedWards["speedcrashes_per_area"]=speedWards["number_of_speedcrashes"] / speedWards["st_area_sh"]
speedWards.ward = speedWards.ward.astype('float64').astype(str)
speedWards=speedWards.merge(speedcam_counts_per_ward, on='ward',how='left')
speedWards=speedWards.fillna(0)

base=speedWards.plot(figsize=(14,12), column='speedcrashes_per_area', cmap='OrRd', linewidth=2, legend=True)
Speedcam_crashes_by_ward.plot(ax=base,figsize=(14,12),marker='P', color='blue', markersize=20, edgecolor='ghostwhite')
<Axes: >
_images/45c23b679e39abf51a78c5047fe381f4ca45c0d6efc422cb59750ff34bffabe9.png
speedWards.sort_values(by='speedcrashes_per_area', ascending=False)
ward objectid date_edit_ time_edit_ ward_id globalid st_area_sh st_length_ geometry number_of_speedcrashes speedcrashes_per_area cameras
1 2.0 52.0 2022-06-01 00:00:00.000 2.0 {88F300F6-D6DF-4337-8DE3-0C2D27A5B338} 3.128511e+07 74175.949239 POLYGON ((-87.62517 41.90400, -87.62500 41.904... 101 3.228373e-06 0.0
41 42.0 92.0 2022-06-01 00:00:00.000 42.0 {AE139837-FCC1-4E2A-84A3-15B2B67D65A4} 5.253453e+07 68484.113474 POLYGON ((-87.62685 41.89668, -87.62685 41.896... 163 3.102721e-06 5.0
33 34.0 84.0 2022-06-01 00:00:00.000 34.0 {54EBC7A4-FE32-4936-A72D-33A39D37248F} 4.272862e+07 75371.506020 POLYGON ((-87.63968 41.88906, -87.63924 41.887... 71 1.661650e-06 0.0
0 1.0 51.0 2022-06-01 00:00:00.000 1.0 {DB2A2A7D-FAF1-42A4-B061-AE18C31A80BB} 6.589346e+07 61878.821587 POLYGON ((-87.68777 41.92858, -87.68776 41.928... 83 1.259609e-06 3.0
36 37.0 87.0 2022-06-01 00:00:00.000 37.0 {35FCA85E-7EA3-4399-9077-7EACCF85268E} 1.004835e+08 56306.600969 POLYGON ((-87.72266 41.90316, -87.72266 41.903... 126 1.253937e-06 3.0
30 31.0 81.0 2022-06-01 00:00:00.000 31.0 {0E9C61BE-C5B1-4051-AB5C-833CB7887482} 7.442608e+07 52347.368005 POLYGON ((-87.72392 41.93913, -87.72371 41.939... 84 1.128637e-06 3.0
34 35.0 85.0 2022-06-01 00:00:00.000 35.0 {3FDB81BF-D813-4AA7-9F92-DD74FD23B646} 7.613137e+07 70987.979595 POLYGON ((-87.69620 41.94670, -87.69620 41.946... 85 1.116491e-06 2.0
3 4.0 54.0 2022-06-01 00:00:00.000 4.0 {02DC7BBB-BD1E-413C-994E-0A3154FD3D54} 1.158091e+08 103594.867171 POLYGON ((-87.62429 41.87700, -87.62429 41.876... 127 1.096632e-06 2.0
14 15.0 65.0 2022-06-01 00:00:00.000 15.0 {51F05987-1A65-4707-B17E-98C8709061B1} 8.307862e+07 107657.780595 POLYGON ((-87.63584 41.80905, -87.63585 41.809... 89 1.071274e-06 5.0
2 3.0 53.0 2022-06-01 00:00:00.000 3.0 {4F169974-0F93-4C35-98C1-20A8415C72F5} 9.777341e+07 85625.597620 POLYGON ((-87.61992 41.86577, -87.61985 41.865... 101 1.033001e-06 0.0
27 28.0 78.0 2022-06-01 00:00:00.000 28.0 {65BDECD2-AB03-4F1B-8025-49E3B1029A49} 1.600439e+08 129592.820270 POLYGON ((-87.72098 41.88802, -87.71974 41.888... 158 9.872291e-07 6.0
26 27.0 77.0 2022-06-01 00:00:00.000 27.0 {5EFBE372-72FB-4702-8C3C-BA882825EEF1} 1.595750e+08 129446.885360 POLYGON ((-87.63420 41.89660, -87.63426 41.896... 155 9.713300e-07 2.0
15 16.0 66.0 2022-06-01 00:00:00.000 16.0 {B54690B6-21DF-44F5-B898-D73EF9976BDC} 1.258524e+08 90382.506038 POLYGON ((-87.64077 41.77616, -87.64082 41.776... 122 9.693898e-07 1.0
5 6.0 56.0 2022-06-01 00:00:00.000 6.0 {FD74A999-4BBA-4CE3-BEBB-CC76423037E8} 1.392022e+08 80779.851890 POLYGON ((-87.61794 41.77292, -87.61786 41.772... 134 9.626284e-07 3.0
35 36.0 86.0 2022-06-01 00:00:00.000 36.0 {337BAF17-7684-4F7F-BFCA-0BFD2B92B869} 8.383845e+07 118667.485047 POLYGON ((-87.76599 41.92398, -87.76591 41.923... 80 9.542162e-07 5.0
4 5.0 55.0 2022-06-01 00:00:00.000 5.0 {0A109A41-9DED-47D7-934E-1EA1CC7EE025} 1.120803e+08 88207.690241 POLYGON ((-87.56030 41.76636, -87.56058 41.766... 95 8.476069e-07 3.0
16 17.0 67.0 2022-06-01 00:00:00.000 17.0 {A0475DAB-473E-447B-9F82-AEC0CA483C93} 1.301704e+08 90154.781522 POLYGON ((-87.65421 41.76869, -87.65421 41.768... 110 8.450464e-07 5.0
20 21.0 71.0 2022-06-01 00:00:00.000 21.0 {BA7C81E8-7DEB-46DF-8E71-95F9AE112FF3} 2.118767e+08 92642.006031 POLYGON ((-87.62405 41.73014, -87.62410 41.730... 174 8.212322e-07 1.0
46 47.0 97.0 2022-06-01 00:00:00.000 47.0 {4F17B913-08A1-4EF6-BF20-0EF4B6478494} 8.481029e+07 55157.008247 POLYGON ((-87.65979 41.97332, -87.65978 41.973... 69 8.135805e-07 5.0
28 29.0 79.0 2022-06-01 00:00:00.000 29.0 {C1A9937E-2864-4CFB-ADD5-B8397C56DC77} 1.193660e+08 97816.079177 POLYGON ((-87.80127 41.93944, -87.80127 41.939... 96 8.042494e-07 3.0
42 43.0 93.0 2022-06-01 00:00:00.000 43.0 {1003F8BC-CAE5-46E7-8A50-95CC5B60E8C7} 6.223707e+07 48459.476947 POLYGON ((-87.63183 41.93305, -87.63183 41.932... 50 8.033797e-07 0.0
22 23.0 73.0 2022-06-01 00:00:00.000 23.0 {51BB999E-306A-4091-8F7E-4241AACA3340} 1.168305e+08 94602.226753 POLYGON ((-87.71024 41.77156, -87.71039 41.771... 91 7.789062e-07 2.0
47 48.0 98.0 2022-06-01 00:00:00.000 48.0 {174DEC8E-5281-4774-831E-A7E0F6F3440D} 4.500890e+07 35618.125393 POLYGON ((-87.64430 41.96990, -87.64516 41.969... 35 7.776239e-07 1.0
32 33.0 83.0 2022-06-01 00:00:00.000 33.0 {F01E135A-54DB-49B2-867E-7F2DCD35A1F6} 6.217322e+07 48801.435311 POLYGON ((-87.70353 41.97186, -87.70344 41.971... 48 7.720366e-07 2.0
19 20.0 70.0 2022-06-01 00:00:00.000 20.0 {1EA93731-81AC-42D6-9711-283C3A3CA2BE} 1.453499e+08 100221.251179 POLYGON ((-87.62082 41.79383, -87.62050 41.793... 112 7.705545e-07 5.0
25 26.0 76.0 2022-06-01 00:00:00.000 26.0 {BB18C0C9-4A3A-43F8-A953-6A8B4D2487D5} 7.767961e+07 60930.848090 POLYGON ((-87.73649 41.92253, -87.73648 41.922... 59 7.595301e-07 6.0
31 32.0 82.0 2022-06-01 00:00:00.000 32.0 {2106D44D-07AC-4B39-A878-BEBB439D1BF3} 9.288828e+07 47973.924224 POLYGON ((-87.68097 41.94636, -87.68097 41.946... 70 7.535934e-07 8.0
13 14.0 64.0 2022-06-01 00:00:00.000 14.0 {612295DC-E128-468C-B0C9-A1ADE1CB1C84} 1.213109e+08 72296.250663 POLYGON ((-87.69421 41.80828, -87.69420 41.808... 89 7.336524e-07 9.0
23 24.0 74.0 2022-06-01 00:00:00.000 24.0 {9ED052F7-F703-4A2D-A829-363FB60472C4} 1.120000e+08 68816.597232 POLYGON ((-87.69070 41.85635, -87.69077 41.856... 81 7.232144e-07 4.0
24 25.0 75.0 2022-06-01 00:00:00.000 25.0 {B1A8F67E-3BEB-4E6A-967B-DB2271B162C5} 9.329780e+07 80678.887175 POLYGON ((-87.63901 41.86002, -87.63901 41.859... 67 7.181306e-07 1.0
11 12.0 62.0 2022-06-01 00:00:00.000 12.0 {EAD019CB-AA66-48C4-9338-795B4E083B59} 1.334616e+08 76139.484398 POLYGON ((-87.66588 41.84493, -87.66581 41.844... 95 7.118152e-07 1.0
7 8.0 58.0 2022-06-01 00:00:00.000 8.0 {2B5945BD-349C-4088-9B25-D99D4FB6C01D} 1.799926e+08 77255.568224 POLYGON ((-87.58587 41.76424, -87.58597 41.764... 115 6.389150e-07 2.0
29 30.0 80.0 2022-06-01 00:00:00.000 30.0 {15C33223-51B6-456F-B790-BEC795885C33} 9.490456e+07 81414.586459 POLYGON ((-87.73242 41.95181, -87.73242 41.951... 58 6.111403e-07 5.0
48 49.0 99.0 2022-06-01 00:00:00.000 49.0 {F7B2FFFC-D9B6-463F-BFF0-8C5C2ED72D47} 5.088363e+07 37398.359952 POLYGON ((-87.65729 42.00418, -87.65729 42.004... 31 6.092332e-07 0.0
49 50.0 100.0 2022-06-01 00:00:00.000 50.0 {C4F10402-10E2-4401-BD4D-7FBDAF35E3FC} 7.450479e+07 60789.219509 POLYGON ((-87.68189 42.00896, -87.68204 42.008... 45 6.039880e-07 0.0
44 45.0 95.0 2022-06-01 00:00:00.000 45.0 {18480250-3E08-4D68-BF2E-96E27F6503B5} 1.394346e+08 117115.300022 POLYGON ((-87.77310 42.01148, -87.77309 42.011... 82 5.880892e-07 2.0
12 13.0 63.0 2022-06-01 00:00:00.000 13.0 {883D9536-9DDE-4FB8-B340-E9A644FD1851} 1.480001e+08 59975.600111 POLYGON ((-87.74205 41.77113, -87.74206 41.771... 87 5.878374e-07 0.0
43 44.0 94.0 2022-06-01 00:00:00.000 44.0 {E181C590-6E28-4CF9-85A1-96AF19075184} 4.750785e+07 36707.423435 POLYGON ((-87.65682 41.95140, -87.65681 41.951... 27 5.683272e-07 0.0
37 38.0 88.0 2022-06-01 00:00:00.000 38.0 {6E5F0557-2DCA-490E-8E7D-C5B58CA65DFA} 1.775660e+08 91571.573668 POLYGON ((-87.75961 41.95327, -87.75964 41.953... 98 5.519076e-07 7.0
18 19.0 69.0 2022-06-01 00:00:00.000 19.0 {91001AF5-B4E0-4F45-A1CB-7C22070BA22D} 2.199899e+08 101405.125517 POLYGON ((-87.66674 41.73022, -87.66677 41.730... 121 5.500252e-07 4.0
21 22.0 72.0 2022-06-01 00:00:00.000 22.0 {0705D4DE-80BF-473A-B3B7-078D63AD0298} 1.055096e+08 60413.987154 POLYGON ((-87.70761 41.84995, -87.70761 41.849... 58 5.497128e-07 0.0
6 7.0 57.0 2022-06-01 00:00:00.000 7.0 {279FCBD9-EA0D-4FFC-A8CA-EDA2676C0721} 1.414924e+08 98906.567862 POLYGON ((-87.54393 41.76030, -87.54370 41.760... 72 5.088612e-07 0.0
10 11.0 61.0 2022-06-01 00:00:00.000 11.0 {C7397C87-C4AE-4C48-A00E-50D2CD1100CF} 1.273484e+08 64972.869726 POLYGON ((-87.63600 41.81635, -87.63602 41.816... 60 4.711484e-07 1.0
17 18.0 68.0 2022-06-01 00:00:00.000 18.0 {E22B6995-91F8-4C49-A9F3-4085D503F2A4} 1.933789e+08 79337.751930 POLYGON ((-87.65830 41.73950, -87.65834 41.739... 85 4.395517e-07 10.0
45 46.0 96.0 2022-06-01 00:00:00.000 46.0 {C894F602-BEBF-4984-803F-736F2BB8F6DE} 5.592727e+07 52699.506856 POLYGON ((-87.64521 41.96974, -87.64516 41.969... 23 4.112484e-07 3.0
39 40.0 90.0 2022-06-01 00:00:00.000 40.0 {EA278E33-45CB-4D28-BEE1-F64C155E65B9} 9.664484e+07 67854.255079 POLYGON ((-87.68152 42.00812, -87.68144 42.007... 37 3.828451e-07 1.0
38 39.0 89.0 2022-06-01 00:00:00.000 39.0 {15480A27-2480-40CF-91EC-72B090F03522} 1.818672e+08 77704.757487 POLYGON ((-87.69916 41.98312, -87.69915 41.982... 62 3.409082e-07 8.0
8 9.0 59.0 2022-06-01 00:00:00.000 9.0 {B75B90E6-CB95-4890-BBC3-D2F313E2EE80} 2.344895e+08 102227.294779 POLYGON ((-87.61414 41.72189, -87.61414 41.721... 54 2.302875e-07 2.0
9 10.0 60.0 2022-06-01 00:00:00.000 10.0 {19FF2026-6DDD-45DA-8DF6-B44B0C15834C} 5.773395e+08 147455.404991 POLYGON ((-87.53018 41.74310, -87.53008 41.742... 80 1.385667e-07 4.0
40 41.0 91.0 2022-06-01 00:00:00.000 41.0 {C885247A-E064-4FCF-A35A-747DEC142421} 4.754967e+08 218605.417697 POLYGON ((-87.79065 42.00040, -87.79058 42.000... 62 1.303900e-07 1.0
x1=speedWards.cameras
y1=speedWards.speedcrashes_per_area

plt.scatter(x1,y1)

z1=np.polyfit(x1, y1, 1)
p1 = np.poly1d(z1)
plt.plot(x1,p1(x1),"r")
plt.xlabel("Speed Cameras")
plt.ylabel("Density of Speed Caused Crashes")

plt.savefig('SpeedCausedCrashCorrelation.png',dpi=300)
plt.show()
_images/bba58bc02a49268bedcf0438fb4831f4b6fde55570b1fa574030cc03c4512cf8.png
#Finding the covariance
covariance1 = np.cov(x1, y1)
print(covariance1)

#Finding Pearson's correlation p-value
corr1, _ = pearsonr(x1,y1)
print('Pearsons correlation: %.3f' % corr1)

#Finding Spearmans correlation p-value, which is helpful for understanding nonlinear relationships
corr1, _ = spearmanr(x1, y1)
print('Spearmans correlation: %.3f' % corr1)
[[ 6.72816327e+00 -1.04108586e-07]
 [-1.04108586e-07  3.14422055e-13]]
Pearsons correlation: -0.072
Spearmans correlation: 0.037
#The p-value changes, but is still insignificant. 
#Analyzing this data by ward could be problematic, but is still important since alderman have control over a lot of traffic changes in their wards.
#plot the speed cameras against the crash points as a base map. This gives us a little more granular view. 
#A more granular view is important because speed cameras are extremely localized. Usually, they only capture one direction of traffic on one street in one intersection.
base=TrafficCrashes.plot(markersize=1, color='silver', figsize=(20,16))
Speedcam_crashes_by_ward.plot(ax=base,figsize=(14,12),marker='P', color='blue', markersize=40, edgecolor='lightblue')
<Axes: >
_images/36c21c4d18719688931982d488facfffaec1da9e81b6fd26ebd4169df93b2b31.png

With my previous methods of mapping, it is still too difficult to see the details of this data. Below, I begin to use folium so I can interact with the map and gain more insights.

Wards.dtypes
ward                   object
objectid              float64
date_edit_             object
time_edit_             object
ward_id               float64
globalid               object
st_area_sh            float64
st_length_            float64
geometry             geometry
number_of_crashes       int64
crashes_per_area      float64
cameras               float64
dtype: object
#additional libraries need to be imported for this method.
#I will similarily utilize the choropleth map as the first map layer and plot the speed camera locations on top.
#The main benefits of this method is that I can interact with the map, zoom in and out, and use a basemap that have detailed street geography.
#This makes it easier for me to look at street intersections, highway locations, parks, etc.

import json
import folium

#we must convert the date column to a string because a date field cannot be converted to geojson
Speedcam_crashes_by_ward['GO-LIVE DATE']=Speedcam_crashes_by_ward['GO-LIVE DATE'].astype(str)

speedcam_gjson = folium.features.GeoJson(Speedcam_crashes_by_ward, 
                                         name = "Speed Camera Locations",
                                        marker=folium.CircleMarker(radius=7,fill_color="grey", fill_opacity=0.7, color="black",weight=3),
                                        tooltip=folium.GeoJsonTooltip(fields=['ADDRESS','GO-LIVE DATE','FIRST APPROACH','SECOND APPROACH','ward']))

fmap = folium.Map(location=[41.8,-87.6], zoom_start=11)

folium.Choropleth(
    geo_data= Wards,
    name="choropleth",
    data=Wards,
    columns = ["ward", "crashes_per_area"],
    key_on="feature.properties.ward",
    fill_color="YlOrBr",
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name="Crash Density",).add_to(fmap)

speedcam_gjson.add_to(fmap)
folium.LayerControl().add_to(fmap)

fmap
Make this Notebook Trusted to load map: File -> Trust Notebook
#Taking this method a step further, I decide to get rid of the ward boundaires and look specifically as concentrated ares of crashes.
#In order to do this, I will utilize a folium plug in that takes point data (crash data in my map) and transforms it into a heat map.
#I plot the speed cameras on top.
#Now, I am able to look at the speed camera locations and determine if there are concentrations of crashes nearby.
#This type of map can also be important for determining locations for new speed cameras to improve safety.

from folium import plugins

heatmap = folium.Map(location = [41.922446, -87.674360], zoom_start=14.8)
heat_data = [[point.xy[1][0], point.xy[0][0]] for point in TrafficCrashes.geometry]
heat_data
speedcam_gjson.add_to(heatmap)
plugins.HeatMap(heat_data).add_to(heatmap)
heatmap.save('heatmap.html')
heatmap
Make this Notebook Trusted to load map: File -> Trust Notebook
#repeating these steps with the data that only includes speed caused crashes

heatmap2 = folium.Map(location = [41.922446, -87.674360], zoom_start=14.8)
heat_data2 = [[point.xy[1][0], point.xy[0][0]] for point in SpeedCrashes.geometry]
heat_data2
speedcam_gjson.add_to(heatmap2)
plugins.HeatMap(heat_data2).add_to(heatmap2)

heatmap2
Make this Notebook Trusted to load map: File -> Trust Notebook

Using Folium allows me to investigate certain areas and hotspots.

Zooming in and out of the data allows me to see target areas for intervention.

The map showing only speed related crashes helps show that the speed cameras are effective in preventing certain types of crashes in certain areas.